#include "thirdparty/logging/async_logging.h"

namespace logging {
AsyncLogging::AsyncLogging(const std::string& base_dir)
    :running_(true),current_buffer_(std::make_unique<LargeBuffer>()),
    backend_buffer_(std::make_unique<LargeBuffer>()),
    async_excutor_(std::bind(&AsyncLogging::ThreadFunction, this)){
  std::cout << "base_dir=" << base_dir << std::endl;
}

void AsyncLogging::OutputLog(const char* data, uint32_t len) {
  std::lock_guard<std::mutex> lk(buf_mutex_);
  if (current_buffer_->RemainLen() < len) {
    buffers_.push_back(std::move(current_buffer_));
    if (backend_buffer_) {
      current_buffer_ = std::move(backend_buffer_);
    } else {
      current_buffer_ = std::make_unique<LargeBuffer>();
    }
    current_buffer_->Append(data, len);
    buffers_no_empty_cond_.notify_one();
  } else {
    current_buffer_->Append(data, len);
  }
}

void AsyncLogging::ThreadFunction() {
  LargeBufferPtr tmp1 = std::make_unique<LargeBuffer>();
  LargeBufferPtr tmp2 = std::make_unique<LargeBuffer>();
  while(running_) {
    {
      std::unique_lock<std::mutex> lk(buf_mutex_);
      if (buffers_no_empty_cond_.wait_for(lk,
              std::chrono::seconds(kFlushInterval),
              [&]() {return buffers_.size() > 0 || current_buffer_->Size() > 0;})) {
        buffers_.push_back(std::move(current_buffer_));
        write_buffers_.swap(buffers_);
        current_buffer_ = std::move(tmp1);
        if (!backend_buffer_) {
          backend_buffer_ = std::move(tmp2);
        }
      } else {
        continue;
      }
    }
    if (write_buffers_.size() > 16) {
      write_buffers_.erase(write_buffers_.begin() + 16);
      std::cerr << "log too mush,ignore some" << std::endl;
    }
    for (const auto& ptr : write_buffers_) {
      fwrite(ptr->CStr(), 1, ptr->Size(), stdout);
    }
    tmp1 = std::move(write_buffers_.back());
    tmp1->Reset();
    write_buffers_.pop_back();
    if (!tmp2) {
      tmp2 = std::move(write_buffers_.back());
      write_buffers_.pop_back();
      tmp2->Reset();
    }
    write_buffers_.clear();
  }
}
}
